package com.engine.salary.entity.salaryacct.bo;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import com.engine.salary.annotation.SalaryFormulaVar;
import com.engine.salary.component.WeaTableColumnGroup;
import com.engine.salary.constant.SalaryDefaultTenantConstant;
import com.engine.salary.entity.datacollection.DataCollectionEmployee;
import com.engine.salary.entity.salaryacct.dto.ConsolidatedTaxDetailDTO;
import com.engine.salary.entity.salaryacct.dto.SalaryAcctEmployeeInfoDTO;
import com.engine.salary.entity.salaryacct.dto.SalaryAcctResultDetailDTO;
import com.engine.salary.entity.salaryacct.dto.SalaryAcctResultListColumnDTO;
import com.engine.salary.entity.salaryacct.param.SalaryAcctResultSaveParam;
import com.engine.salary.entity.salaryacct.po.*;
import com.engine.salary.entity.salaryformula.dto.SalaryFormulaEmployeeDTO;
import com.engine.salary.entity.salaryitem.po.SalaryItemPO;
import com.engine.salary.entity.salarysob.dto.SalarySobEmpFieldDTO;
import com.engine.salary.entity.salarysob.dto.SalarySobItemAggregateDTO;
import com.engine.salary.entity.salarysob.dto.SalarySobItemDTO;
import com.engine.salary.entity.salarysob.dto.SalarySobItemGroupDTO;
import com.engine.salary.entity.salarysob.po.*;
import com.engine.salary.entity.taxagent.po.TaxAgentPO;
import com.engine.salary.enums.AccountTypeEnum;
import com.engine.salary.enums.SalaryValueTypeEnum;
import com.engine.salary.enums.UserStatusEnum;
import com.engine.salary.enums.salaryaccounting.LockStatusEnum;
import com.engine.salary.enums.salaryitem.SalaryDataTypeEnum;
import com.engine.salary.util.SalaryEntityUtil;
import com.engine.salary.util.SalaryI18nUtil;
import com.engine.salary.util.page.SalaryPageUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.beans.BeanUtils;
import weaver.general.Util;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 薪资核算结果
 * <p>Copyright: Copyright (c) 2022</p>
 * <p>Company: 泛微软件</p>
 *
 * @author qiantao
 * @version 1.0
 **/
public class SalaryAcctResultBO {

    /**
     * 数据类型的后缀标识
     * 为了展示千分位，薪资核算结果列表、线上线下对比结果列表需要返回给前端列表字段的数据类型，字段索引+后缀标识
     */
    private static final String DATA_TYPE_SUFFIX = "_type";

//    /**
//     * 构建薪资核算结果列表的表头（线下对比）
//     *
//     * @param salarySobItemAggregateDTO
//     * @return
//     */
//    public static List<WeaTableColumn> buildTableColumns4ComparisonResult(SalarySobItemAggregateDTO salarySobItemAggregateDTO, Set<Long> excludeSalaryItemIds) {
//        List<WeaTableColumn> columns = Lists.newArrayList();
//        // 员工信息字段
//        for (SalarySobEmpFieldDTO salarySobEmpFieldDTO : salarySobItemAggregateDTO.getEmpFields()) {
//            columns.add(new WeaTableColumn("150", salarySobEmpFieldDTO.getFieldName(), salarySobEmpFieldDTO.getFieldId()));
//        }
//        // 薪资项目分组下的薪资项目
//        for (SalarySobItemGroupDTO salarySobItemGroupDTO : salarySobItemAggregateDTO.getItemGroups()) {
//            if (CollectionUtils.isEmpty(salarySobItemGroupDTO.getItems())) {
//                continue;
//            }
//            for (SalarySobItemDTO salarySobItemDTO : salarySobItemGroupDTO.getItems()) {
//                if (excludeSalaryItemIds.contains(salarySobItemDTO.getSalaryItemId())) {
//                    continue;
//                }
//                columns.add(new WeaTableColumn("150", salarySobItemDTO.getName(), "" + salarySobItemDTO.getSalaryItemId()));
//            }
//        }
//        // 没有分类的薪资项目
//        for (SalarySobItemDTO salarySobItemDTO : salarySobItemAggregateDTO.getItems()) {
//            if (excludeSalaryItemIds.contains(salarySobItemDTO.getSalaryItemId())) {
//                continue;
//            }
//            columns.add(new WeaTableColumn("150", salarySobItemDTO.getName(), "" + salarySobItemDTO.getSalaryItemId()));
//        }
//        return columns;
//    }


    /**
     * 构建薪资核算结果列表的表头（线下对比）
     *
     * @param salarySobItemAggregateDTO
     * @return
     */
    public static List<WeaTableColumnGroup> buildTableColumns4ComparisonResult(SalarySobItemAggregateDTO salarySobItemAggregateDTO, Set<Long> excludeSalaryItemIds) {
        List<WeaTableColumnGroup> columns = Lists.newArrayList();
        // 员工信息字段
        for (SalarySobEmpFieldDTO salarySobEmpFieldDTO : salarySobItemAggregateDTO.getEmpFields()) {
            columns.add(new WeaTableColumnGroup("150", salarySobEmpFieldDTO.getFieldName(), salarySobEmpFieldDTO.getFieldId(), salarySobEmpFieldDTO.getFieldId()));
        }
        // 薪资项目分组下的薪资项目
        for (SalarySobItemGroupDTO salarySobItemGroupDTO : salarySobItemAggregateDTO.getItemGroups()) {
            if (CollectionUtils.isEmpty(salarySobItemGroupDTO.getItems())) {
                continue;
            }
            List<WeaTableColumnGroup> childrenColumns = Lists.newArrayList();
            for (SalarySobItemDTO salarySobItemDTO : salarySobItemGroupDTO.getItems()) {
                if (excludeSalaryItemIds.contains(salarySobItemDTO.getSalaryItemId())) {
                    continue;
                }
                childrenColumns.add(new WeaTableColumnGroup("150", salarySobItemDTO.getName(), "" + salarySobItemDTO.getSalaryItemId(), "" + salarySobItemDTO.getSalaryItemId()));
            }
            WeaTableColumnGroup weaTableColumnWapper = new WeaTableColumnGroup("150", salarySobItemGroupDTO.getName(), String.valueOf(salarySobItemGroupDTO.getId()), childrenColumns);
            columns.add(weaTableColumnWapper);
        }
        // 没有分类的薪资项目
        for (SalarySobItemDTO salarySobItemDTO : salarySobItemAggregateDTO.getItems()) {
            if (excludeSalaryItemIds.contains(salarySobItemDTO.getSalaryItemId())) {
                continue;
            }
            columns.add(new WeaTableColumnGroup("150", salarySobItemDTO.getName(), "" + salarySobItemDTO.getSalaryItemId(), "" + salarySobItemDTO.getSalaryItemId()));
        }
        return columns;
    }

    /**
     * 构建薪资核算结果列表的表头（线下对比）
     *
     * @param salarySobItemAggregateDTO
     * @return
     */
    public static List<WeaTableColumnGroup> buildTableColumns4ComparisonResultByGroup(SalarySobItemAggregateDTO salarySobItemAggregateDTO, Set<Long> excludeSalaryItemIds) {
        List<WeaTableColumnGroup> columns = Lists.newArrayList();
        // 员工信息字段
        for (SalarySobEmpFieldDTO salarySobEmpFieldDTO : salarySobItemAggregateDTO.getEmpFields()) {
            columns.add(new WeaTableColumnGroup("150", salarySobEmpFieldDTO.getFieldName(), salarySobEmpFieldDTO.getFieldId(), salarySobEmpFieldDTO.getFieldId()));
        }
        // 薪资项目分组下的薪资项目
        for (SalarySobItemGroupDTO salarySobItemGroupDTO : salarySobItemAggregateDTO.getItemGroups()) {
            if (CollectionUtils.isEmpty(salarySobItemGroupDTO.getItems())) {
                continue;
            }
            List<WeaTableColumnGroup> childrenColumns = Lists.newArrayList();
            for (SalarySobItemDTO salarySobItemDTO : salarySobItemGroupDTO.getItems()) {
                if (excludeSalaryItemIds.contains(salarySobItemDTO.getSalaryItemId())) {
                    continue;
                }
                childrenColumns.add(new WeaTableColumnGroup("150", salarySobItemDTO.getName(), "" + salarySobItemDTO.getSalaryItemId(), "" + salarySobItemDTO.getSalaryItemId()));
            }
            WeaTableColumnGroup weaTableColumnWapper = new WeaTableColumnGroup("150", salarySobItemGroupDTO.getName(), String.valueOf(salarySobItemGroupDTO.getId()), childrenColumns);
            columns.add(weaTableColumnWapper);
        }
        // 没有分类的薪资项目
        for (SalarySobItemDTO salarySobItemDTO : salarySobItemAggregateDTO.getItems()) {
            if (excludeSalaryItemIds.contains(salarySobItemDTO.getSalaryItemId())) {
                continue;
            }
            columns.add(new WeaTableColumnGroup("150", salarySobItemDTO.getName(), "" + salarySobItemDTO.getSalaryItemId(), "" + salarySobItemDTO.getSalaryItemId()));
        }
        return columns;
    }

    /**
     * 构建薪资核算结果列表的表头
     *
     * @param salarySobItemAggregateDTO
     * @return
     */
    public static List<WeaTableColumnGroup> buildTableColumns(SalarySobItemAggregateDTO salarySobItemAggregateDTO, List<Long> lockSalaryItemIds) {
        List<WeaTableColumnGroup> columns = Lists.newArrayList();
        // 员工信息字段
        for (SalarySobEmpFieldDTO salarySobEmpFieldDTO : salarySobItemAggregateDTO.getEmpFields()) {
            columns.add(new WeaTableColumnGroup(SalaryPageUtil.selfAdaption(salarySobEmpFieldDTO.getFieldName(), 0), salarySobEmpFieldDTO.getFieldName(), salarySobEmpFieldDTO.getFieldId()));
        }
        // 薪资项目分组下的薪资项目
        for (SalarySobItemGroupDTO salarySobItemGroupDTO : salarySobItemAggregateDTO.getItemGroups()) {
            if (CollectionUtils.isEmpty(salarySobItemGroupDTO.getItems())) {
                continue;
            }
            List<WeaTableColumnGroup> childrenColumns = Lists.newArrayList();
            for (SalarySobItemDTO salarySobItemDTO : salarySobItemGroupDTO.getItems()) {
                if (lockSalaryItemIds.contains(salarySobItemDTO.getSalaryItemId())) {
                    childrenColumns.add(new WeaTableColumnGroup(SalaryPageUtil.selfAdaption(salarySobItemDTO.getName(), salarySobItemDTO.getWidth()), salarySobItemDTO.getName(), "" + salarySobItemDTO.getSalaryItemId(), LockStatusEnum.LOCK.getDefaultLabel(), salarySobItemDTO.getPattern(), salarySobItemDTO.getDataType()));
                } else {
                    childrenColumns.add(new WeaTableColumnGroup(SalaryPageUtil.selfAdaption(salarySobItemDTO.getName(), salarySobItemDTO.getWidth()), salarySobItemDTO.getName(), "" + salarySobItemDTO.getSalaryItemId(), LockStatusEnum.UNLOCK.getDefaultLabel(), salarySobItemDTO.getPattern(), salarySobItemDTO.getDataType()));
                }
            }
            WeaTableColumnGroup weaTableColumnWapper = new WeaTableColumnGroup(SalaryPageUtil.selfAdaption(salarySobItemGroupDTO.getName(), 0), salarySobItemGroupDTO.getName(), String.valueOf(salarySobItemGroupDTO.getId()), childrenColumns);
            columns.add(weaTableColumnWapper);
        }
        // 没有分类的薪资项目
        for (SalarySobItemDTO salarySobItemDTO : salarySobItemAggregateDTO.getItems()) {
            if (lockSalaryItemIds.contains(salarySobItemDTO.getSalaryItemId())) {
                columns.add(new WeaTableColumnGroup(SalaryPageUtil.selfAdaption(salarySobItemDTO.getName(), salarySobItemDTO.getWidth()), salarySobItemDTO.getName(), "" + salarySobItemDTO.getSalaryItemId(), LockStatusEnum.LOCK.getDefaultLabel(), salarySobItemDTO.getPattern(), salarySobItemDTO.getDataType()));
            } else {
                columns.add(new WeaTableColumnGroup(SalaryPageUtil.selfAdaption(salarySobItemDTO.getName(), salarySobItemDTO.getWidth()), salarySobItemDTO.getName(), "" + salarySobItemDTO.getSalaryItemId(), LockStatusEnum.UNLOCK.getDefaultLabel(), salarySobItemDTO.getPattern(), salarySobItemDTO.getDataType()));
            }

        }
        // 回算的薪资项目
        for (SalarySobItemDTO salarySobItemDTO : salarySobItemAggregateDTO.getBackCalcItems()) {
            if (lockSalaryItemIds.contains(salarySobItemDTO.getSalaryItemId())) {
                columns.add(new WeaTableColumnGroup(SalaryPageUtil.selfAdaption(salarySobItemDTO.getName(), 0), salarySobItemDTO.getName(), "" + salarySobItemDTO.getSalaryItemId(), LockStatusEnum.LOCK.getDefaultLabel(), salarySobItemDTO.getPattern(), salarySobItemDTO.getDataType()));
            } else {
                columns.add(new WeaTableColumnGroup(SalaryPageUtil.selfAdaption(salarySobItemDTO.getName(), 0), salarySobItemDTO.getName(), "" + salarySobItemDTO.getSalaryItemId(), LockStatusEnum.UNLOCK.getDefaultLabel(), salarySobItemDTO.getPattern(), salarySobItemDTO.getDataType()));
            }

        }
        return columns;
    }

    /**
     * 构建核算结果表头-供报表使用
     *
     * @param salarySobItemAggregateDTO
     * @return
     */
    public static Map<String, Object> buildColumns(SalarySobItemAggregateDTO salarySobItemAggregateDTO) {
        Map<String, Object> map = new HashMap<>();
        // 员工信息字段
        for (SalarySobEmpFieldDTO salarySobEmpFieldDTO : salarySobItemAggregateDTO.getEmpFields()) {
            map.put(salarySobEmpFieldDTO.getFieldId(), salarySobEmpFieldDTO.getFieldName());
        }
        // 薪资项目分组下的薪资项目
        // 薪资项目分组下的薪资项目
        for (SalarySobItemGroupDTO salarySobItemGroupDTO : salarySobItemAggregateDTO.getItemGroups()) {
            if (CollectionUtils.isEmpty(salarySobItemGroupDTO.getItems())) {
                continue;
            }
            for (SalarySobItemDTO salarySobItemDTO : salarySobItemGroupDTO.getItems()) {
                map.put(salarySobItemDTO.getSalaryItemId() + "", salarySobItemDTO.getName());
            }

        }
        // 没有分类的薪资项目
        for (SalarySobItemDTO salarySobItemDTO : salarySobItemAggregateDTO.getItems()) {
            map.put(salarySobItemDTO.getSalaryItemId() + "", salarySobItemDTO.getName());
        }
        return map;
    }

    /**
     * 转船成薪资核算结果列表的表格数据
     *
     * @param salaryItems
     * @param salarySobEmpFields
     * @param simpleEmployees
     * @param salaryAcctEmployees
     * @param salaryAccountingResults
     * @param taxAgents
     * @param consolidatedTaxSalaryAcctEmpIds
     * @param customBackCalcParameters
     * @param dynamicEmpInfo
     * @return
     */
    public static List<Map<String, Object>> buildTableData(List<SalaryItemPO> salaryItems,
                                                           List<SalarySobEmpFieldPO> salarySobEmpFields,
                                                           List<DataCollectionEmployee> simpleEmployees,
                                                           List<SalaryAcctEmployeePO> salaryAcctEmployees,
                                                           List<SalaryAcctResultPO> salaryAccountingResults,
                                                           List<TaxAgentPO> taxAgents,
                                                           Set<Long> consolidatedTaxSalaryAcctEmpIds,
                                                           Map<Long, String> customParameters,
                                                           Map<Long, String> customBackCalcParameters,
                                                           boolean dynamicEmpInfo) {
        if (CollectionUtils.isEmpty(salaryAcctEmployees)) {
            return Collections.emptyList();
        }
        SalaryI18nUtil.i18nList(salaryAcctEmployees);
        Map<Long, DataCollectionEmployee> employeeMap = SalaryEntityUtil.convert2Map(simpleEmployees, DataCollectionEmployee::getEmployeeId);
        Map<Long, String> taxAgentNameMap = SalaryEntityUtil.convert2Map(taxAgents, TaxAgentPO::getId, TaxAgentPO::getName);
        Map<Long, List<SalaryAcctEmployeePO>> taxAcctEmpsMap = SalaryEntityUtil.group2Map(salaryAcctEmployees, SalaryAcctEmployeePO::getTaxAgentId);
        Map<Long, List<SalaryAcctResultPO>> taxAcctResultMap = SalaryEntityUtil.group2Map(salaryAccountingResults, SalaryAcctResultPO::getTaxAgentId);

        List<Map<String, Object>> result = new ArrayList<>();
        for (Long taxAgentId : taxAcctEmpsMap.keySet()) {
            Map<Long, List<SalaryAcctResultPO>> acctResultMap = SalaryEntityUtil.group2Map(taxAcctResultMap.get(taxAgentId), SalaryAcctResultPO::getEmployeeId);
            List<Map<String, Object>> collect = taxAcctEmpsMap.get(taxAgentId).stream().map(e -> {
                List<SalaryAcctResultPO> acctResult = acctResultMap.getOrDefault(e.getEmployeeId(), Collections.emptyList());
            Map<Long, Object> resultValueMap = SalaryEntityUtil.convert2Map(acctResult,
                    SalaryAcctResultPO::getSalaryItemId, SalaryAcctResultPO::getResultValue);
            Map<Long, String> resultFeedbackValueMap = SalaryEntityUtil.convert2Map(acctResult.stream().filter(r -> StringUtils.isNotBlank(r.getEkFeedback())).collect(Collectors.toList()),
                    SalaryAcctResultPO::getSalaryItemId, SalaryAcctResultPO::getEkFeedback);
                // 薪资项目的值
                Map<String, Object> map = SalaryEntityUtil.convert2Map(salaryItems, o -> "" + o.getId(), o -> resultValueMap.getOrDefault(o.getId(), StringUtils.EMPTY));
                // 薪资项目的字段类型（前端依据这个判断是否需要展示千分位）
                Map<String, String> dataTypeMap = SalaryEntityUtil.convert2Map(salaryItems, salaryItemPO -> salaryItemPO.getId() + DATA_TYPE_SUFFIX, SalaryItemPO::getDataType);
                // 薪资项目反馈信息的值
            Map<String, Object> feedbackMap = new HashMap<>();
            salaryItems.stream().forEach(item -> {
                String feedback = resultFeedbackValueMap.get(item.getId());
                if (StringUtils.isNotBlank(feedback)) {
                    feedbackMap.put(item.getId() + "_feedback", feedback);
                }
            });
            map.putAll(dataTypeMap);
            map.putAll(feedbackMap);
                // 人员信息字段的值
                Map<String, String> fieldValueMap = SalaryAcctFormulaBO.convert2FormulaEmployee(employeeMap.get(e.getEmployeeId()), e, true);
                for (SalarySobEmpFieldPO salarySobEmpField : salarySobEmpFields) {
                    // 员工信息字段的字段类型
                    if (dynamicEmpInfo) {
                        map.put(salarySobEmpField.getFieldCode(), fieldValueMap.get(salarySobEmpField.getFieldCode()));
                    } else {
                        if ("departmentName".equals(salarySobEmpField.getFieldCode())) {
                            map.put("departmentName", e.getDepartmentName());
                        } else if ("departmentId".equals(salarySobEmpField.getFieldCode())) {
                            map.put("departmentId", e.getDepartmentId());
                        } else if ("subcompanyName".equals(salarySobEmpField.getFieldCode())) {
                            map.put("subcompanyName", e.getSubcompanyName());
                        } else if ("subcompanyId".equals(salarySobEmpField.getFieldCode())) {
                            map.put("subcompanyId", e.getSubcompanyId());
                        } else if ("jobcall".equals(salarySobEmpField.getFieldCode())) {
                            map.put("jobcall", e.getJobcall());
                        } else if ("jobcallId".equals(salarySobEmpField.getFieldCode())) {
                            map.put("jobcallId", e.getJobcallId());
                        } else if ("jobtitleName".equals(salarySobEmpField.getFieldCode())) {
                            map.put("jobtitleName", e.getJobtitleName());
                        } else if ("jobtitleId".equals(salarySobEmpField.getFieldCode())) {
                            map.put("jobtitleId", e.getJobtitleId());
                        } else if ("status".equals(salarySobEmpField.getFieldCode())) {
                            map.put("status", e.getStatus());
                        } else if ("statusName".equals(salarySobEmpField.getFieldCode())) {
                            map.put("statusName", UserStatusEnum.getDefaultLabelByValue(new Integer(Util.null2s(e.getStatus(), "1"))));
                        } else if ("accountType".equals(salarySobEmpField.getFieldCode())) {
                            map.put("accountType", e.getAccountType());
                        } else if ("accountTypeName".equals(salarySobEmpField.getFieldCode())) {
                            map.put("accountTypeName", AccountTypeEnum.getDefaultLabelByValue(e.getAccountType()));
                        } else {
                            map.put(salarySobEmpField.getFieldCode(), fieldValueMap.get(salarySobEmpField.getFieldCode()));
                        }
                    }
                    map.put(salarySobEmpField.getFieldCode() + DATA_TYPE_SUFFIX, SalaryDataTypeEnum.STRING.getValue());
                }
                // 主键id
                map.put("id", e.getId());
                //锁定数据
                map.put("lockItems", e.getLockItems() != null ? e.getLockItems().stream().filter(Objects::nonNull).map(Object::toString).collect(Collectors.toList()) : new ArrayList<>());
                //人员id
                map.put("employeeId", e.getEmployeeId());
                // 个税扣缴义务人
                String taxAgentName = taxAgentNameMap.getOrDefault(e.getTaxAgentId(), StringUtils.EMPTY);
                map.put("taxAgentName", taxAgentName);
                // 是否属于"合并计税"的标记
                map.put("consolidatedTaxation", StringUtils.isNotEmpty(taxAgentName) && consolidatedTaxSalaryAcctEmpIds.contains(e.getId()));
                // 个税扣缴义务人的字段类型
                map.put("taxAgentName" + DATA_TYPE_SUFFIX, SalaryDataTypeEnum.STRING.getValue());
                // 公式详情
                customParameters.putAll(customBackCalcParameters);
                map.put("customParameters", customParameters);
                return map;
            }).collect(Collectors.toList());
            result.addAll(collect);
        }
        return result;
    }

    /**
     * 转转成薪资核算线下对比结果
     *
     * @param salaryItems
     * @param salarySobEmpFields
     * @param simpleEmployees
     * @param salaryAcctEmployees
     * @param salaryAcctResultPOS
     * @param excelAcctResultPOS
     * @param taxAgents
     * @param consolidatedTaxSalaryAcctEmpIds
     * @return
     */
    public static List<Map<String, Object>> buildComparisonTableData(List<SalaryItemPO> salaryItems,
                                                                     List<SalarySobEmpFieldPO> salarySobEmpFields,
                                                                     List<DataCollectionEmployee> simpleEmployees,
                                                                     List<SalaryAcctEmployeePO> salaryAcctEmployees,
                                                                     List<SalaryAcctResultPO> salaryAcctResultPOS,
                                                                     List<ExcelAcctResultPO> excelAcctResultPOS,
                                                                     List<TaxAgentPO> taxAgents,
                                                                     Map<Long, String> customParameters,
                                                                     Set<Long> consolidatedTaxSalaryAcctEmpIds,
                                                                     Set<Long> includeSalaryItemIds,
                                                                     boolean dynamicEmpInfo) {
        if (CollectionUtils.isEmpty(simpleEmployees)) {
            return Collections.emptyList();
        }
        Map<Long, List<ExcelAcctResultPO>> excelResultMap = SalaryEntityUtil.group2Map(excelAcctResultPOS, ExcelAcctResultPO::getSalaryAcctEmpId);
        Map<Long, List<SalaryAcctResultPO>> acctResultMap = SalaryEntityUtil.group2Map(salaryAcctResultPOS, SalaryAcctResultPO::getSalaryAcctEmpId);
        Map<Long, String> taxAgentNameMap = SalaryEntityUtil.convert2Map(taxAgents, TaxAgentPO::getId, TaxAgentPO::getName);
        Map<Long, DataCollectionEmployee> employeeMap = SalaryEntityUtil.convert2Map(simpleEmployees, DataCollectionEmployee::getEmployeeId);
        List<Map<String, Object>> resultList = Lists.newArrayListWithExpectedSize(salaryAcctEmployees.size());
        for (SalaryAcctEmployeePO salaryAcctEmployee : salaryAcctEmployees) {
            // 线下值和系统值之间是否存在差异
            boolean different = false;
            Map<String, Object> map = Maps.newHashMap();
            // 员工信息字段的值
            Map<String, String> fieldValueMap = SalaryAcctFormulaBO.convert2FormulaEmployee(employeeMap.get(salaryAcctEmployee.getEmployeeId()), salaryAcctEmployee, false);
            for (SalarySobEmpFieldPO salarySobEmpField : salarySobEmpFields) {
                // 员工信息字段的字段类型
                if (dynamicEmpInfo) {
                    map.put(salarySobEmpField.getFieldCode(), fieldValueMap.get(salarySobEmpField.getFieldCode()));
                } else {
                    if ("departmentName".equals(salarySobEmpField.getFieldCode())) {
                        map.put("departmentName", salaryAcctEmployee.getDepartmentName());
                    } else if ("departmentId".equals(salarySobEmpField.getFieldCode())) {
                        map.put("departmentId", salaryAcctEmployee.getDepartmentId());
                    } else if ("subcompanyName".equals(salarySobEmpField.getFieldCode())) {
                        map.put("subcompanyName", salaryAcctEmployee.getSubcompanyName());
                    } else if ("jobcall".equals(salarySobEmpField.getFieldCode())) {
                        map.put("jobcall", salaryAcctEmployee.getJobcall());
                    } else if ("jobcallId".equals(salarySobEmpField.getFieldCode())) {
                        map.put("jobcallId", salaryAcctEmployee.getJobcallId());
                    } else if ("jobtitleName".equals(salarySobEmpField.getFieldCode())) {
                        map.put("jobtitleName", salaryAcctEmployee.getJobtitleName());
                    } else if ("jobtitleId".equals(salarySobEmpField.getFieldCode())) {
                        map.put("jobtitleId", salaryAcctEmployee.getJobtitleId());
                    } else if ("status".equals(salarySobEmpField.getFieldCode())) {
                        map.put("status", salaryAcctEmployee.getStatus());
                    } else if ("statusName".equals(salarySobEmpField.getFieldCode())) {
                        map.put("statusName", UserStatusEnum.getDefaultLabelByValue(new Integer(Util.null2s(salaryAcctEmployee.getStatus(), "1"))));
                    } else if ("accountType".equals(salarySobEmpField.getFieldCode())) {
                        map.put("accountType", salaryAcctEmployee.getAccountType());
                    } else if ("accountTypeName".equals(salarySobEmpField.getFieldCode())) {
                        map.put("accountTypeName", AccountTypeEnum.getDefaultLabelByValue(salaryAcctEmployee.getAccountType()));
                    } else {
                        map.put(salarySobEmpField.getFieldCode(), fieldValueMap.get(salarySobEmpField.getFieldCode()));
                    }
                }
                map.put(salarySobEmpField.getFieldCode() + DATA_TYPE_SUFFIX, SalaryDataTypeEnum.STRING.getValue());
            }
            // 系统值
            Map<Long, String> acctResultValueMap = SalaryEntityUtil.convert2Map(acctResultMap.getOrDefault(salaryAcctEmployee.getId(), Collections.emptyList()),
                    SalaryAcctResultPO::getSalaryItemId, SalaryAcctResultPO::getResultValue);
            // 线下值
            Map<Long, String> excelResultValueMap = SalaryEntityUtil.convert2Map(excelResultMap.getOrDefault(salaryAcctEmployee.getId(), Collections.emptyList()),
                    ExcelAcctResultPO::getSalaryItemId, ExcelAcctResultPO::getResultValue);
            // 薪资项目字段的值
            for (SalaryItemPO salaryItem : salaryItems) {
                Map<String, Object> temp = Maps.newHashMap();
                // 系统值
                String acctResultValue = acctResultValueMap.get(salaryItem.getId());
                // 线下值
                String excelResultValue = excelResultValueMap.get(salaryItem.getId());
                temp.put("acctResultValue", acctResultValue);
                temp.put("excelResultValue", excelResultValue);
                map.put(String.valueOf(salaryItem.getId()), temp);
                // 薪资项目字段的字段类型
                map.put(salaryItem.getId() + DATA_TYPE_SUFFIX, salaryItem.getDataType());
                SalaryDataTypeEnum dataTypeEnum = SalaryDataTypeEnum.parseByValue(salaryItem.getDataType());
                if (dataTypeEnum == SalaryDataTypeEnum.NUMBER) {
                    if (NumberUtil.isNumber(acctResultValue) && NumberUtil.isNumber(excelResultValue)) {
                        if (new BigDecimal(acctResultValue).compareTo(new BigDecimal(excelResultValue)) != 0) {
                            different = true;
                            includeSalaryItemIds.add(salaryItem.getId());
                        }
                    } else {
                        if (SalaryEntityUtil.empty2Zero(acctResultValue).compareTo(SalaryEntityUtil.empty2Zero(excelResultValue)) != 0) {
                            different = true;
                            includeSalaryItemIds.add(salaryItem.getId());
                        }
                    }
                } else {
                    if (!StringUtils.equals(acctResultValue, excelResultValue)) {
                        different = true;
                        includeSalaryItemIds.add(salaryItem.getId());
                    }
                }
            }
            // 主键id
            map.put("id", salaryAcctEmployee.getId());
            // 个税扣缴义务人
            String taxAgentName = taxAgentNameMap.getOrDefault(salaryAcctEmployee.getTaxAgentId(), StringUtils.EMPTY);
            map.put("taxAgentName", taxAgentName);
            // 个税扣缴义务人的字段类型
            map.put("taxAgentName" + DATA_TYPE_SUFFIX, SalaryDataTypeEnum.STRING.getValue());
            // 是否属于"合并计税"的标记
            map.put("consolidatedTaxation", StringUtils.isNotEmpty(taxAgentName) && consolidatedTaxSalaryAcctEmpIds.contains(salaryAcctEmployee.getId()));
            // 薪资项目的公式详情（前端需要展示）
            map.put("customParameters", customParameters);
            // 是否存在差异的标记
            map.put("different", different);
            resultList.add(map);
        }
        return resultList;
    }

    /**
     * 转换成薪资核算结果详情dto
     *
     * @param simpleEmployee
     * @param taxAgentPO
     * @param salaryAcctEmployee
     * @param salarySobEmpFields
     * @param salarySobItemPOS
     * @param salaryItems
     * @param salaryAcctResults
     * @return
     */
    public static SalaryAcctResultDetailDTO convert2DetailDTO(DataCollectionEmployee simpleEmployee,
                                                              TaxAgentPO taxAgentPO,
                                                              SalaryAcctEmployeePO salaryAcctEmployee,
                                                              List<SalarySobEmpFieldPO> salarySobEmpFields,
                                                              List<SalarySobItemGroupPO> salarySobItemGroupPOS,
                                                              List<SalarySobItemPO> salarySobItemPOS,
                                                              List<SalaryItemPO> salaryItems,
                                                              List<SalaryAcctResultPO> salaryAcctResults,
                                                              List<SalarySobBackItemPO> salarySobBackItemPOS,
                                                              List<SalaryItemPO> salaryBackItemPOS,
                                                              Map<Long, String> salaryBackItemFormula,
                                                              Map<String, SalaryAcctResultListColumnDTO> formulaContentMap,
                                                              List<Long> lockItems) {

        // 员工信息字段
        Map<String, String> employeeFieldValueMap = SalaryAcctFormulaBO.convert2FormulaEmployee(simpleEmployee, salaryAcctEmployee, false);
        // 个税扣缴义务人
        employeeFieldValueMap.put("taxAgentName", Optional.ofNullable(taxAgentPO).map(TaxAgentPO::getName).orElse(StringUtils.EMPTY));
        Map<String, String> employeeFieldNameMap = buildEmployeeFieldName();
        List<String> canEditKeys = Arrays.asList("subcompany", "department", "jobtitle", "jobcall");
        List<SalaryAcctEmployeeInfoDTO> employeeInfos = salarySobEmpFields.stream()
                .map(e -> {
                    String fieldCode = e.getFieldCode();
                    String fieldType = employeeFieldNameMap.getOrDefault(fieldCode + "_type", StringUtils.EMPTY);
                    SalaryAcctEmployeeInfoDTO dto = SalaryAcctEmployeeInfoDTO.builder()
                            .fieldCode(fieldCode)
                            .fieldName(employeeFieldNameMap.getOrDefault(fieldCode, StringUtils.EMPTY))
                            .fieldValue(employeeFieldValueMap.getOrDefault(fieldCode, StringUtils.EMPTY))
                            .fieldType(fieldType)
                            .canEdit(fieldType.contains("Browser") ? true : false)
                            .build();

                    String codeKey = fieldCode.replace("Id", "").replace("Name", "");
                    if (canEditKeys.contains(codeKey)) {
                        // 前端用于回写浏览框
                        Map<String, String> fieldValueMap = new HashMap<>();
                        fieldValueMap.put("id", employeeFieldValueMap.getOrDefault(codeKey + "Id", StringUtils.EMPTY));
                        fieldValueMap.put("name", employeeFieldValueMap.getOrDefault(codeKey + "Name", StringUtils.EMPTY));
                        if (codeKey.equals("jobcall")) {
                            fieldValueMap.put("name", employeeFieldValueMap.getOrDefault("jobcall", StringUtils.EMPTY));
                        }
                        dto.setFieldValue(fieldValueMap);
                    }
                    return dto;
                })
                .collect(Collectors.toList());

        List<String> needRemoveFieldNames = new ArrayList<String>();
        // 过滤出是浏览框类型的且人员信息中同时存在名称和id的字段
        employeeInfos.stream()
                .filter(e -> e.getFieldType().contains("Browser"))
                .map(e -> SalaryAcctEmployeeInfoDTO.builder().fieldName(e.getFieldName().replace("ID", "")).build())
                .collect(Collectors.groupingBy(SalaryAcctEmployeeInfoDTO::getFieldName))
                .forEach((k, v) -> {
                    if (v.size() > 1) {
                        needRemoveFieldNames.add(k + "ID");
                    }
                });

        // 移除字段
        employeeInfos = employeeInfos.stream().filter(info -> !needRemoveFieldNames.contains(info.getFieldName())).collect(Collectors.toList());
        // 薪资项目的值
        Map<Long, String> resultValueMap = SalaryEntityUtil.convert2Map(salaryAcctResults, SalaryAcctResultPO::getSalaryItemId, SalaryAcctResultPO::getResultValue);
        Map<Long, SalaryItemPO> salaryItemMap = SalaryEntityUtil.convert2Map(salaryItems, SalaryItemPO::getId);
        Map<Long, SalaryItemPO> salaryBackItemMap = SalaryEntityUtil.convert2Map(salaryBackItemPOS, SalaryItemPO::getId);
        Map<Long, List<SalarySobItemPO>> salarySobItemPOMap = SalaryEntityUtil.group2Map(salarySobItemPOS, SalarySobItemPO::getSalarySobItemGroupId);

        // 对分组进行排序
        salarySobItemGroupPOS = sortGroup(salarySobItemGroupPOS);
        // 对分组内薪资项目排序
        sortItem(salarySobItemPOMap);
        // 根据账套分组封装薪资项目的值
        List<SalaryAcctResultDetailDTO.SalaryAcctResultDetailItemByGroupDTO> itemsByGroup = new ArrayList<>();
        for (SalarySobItemGroupPO groupPO : salarySobItemGroupPOS) {
            List<SalarySobItemPO> groupItems = salarySobItemPOMap.getOrDefault(groupPO.getId(), Collections.emptyList());
            if (CollectionUtils.isNotEmpty(groupItems)) {
                List<SalaryAcctResultDetailDTO.SalaryAcctResultDetailItemDTO> items = groupItems.stream()
                        .map(salarySobItemPO -> convert2SalaryAcctResultDetailItemDTO(salarySobItemPO, salaryItemMap.get(salarySobItemPO.getSalaryItemId()), resultValueMap, formulaContentMap, lockItems))
                        .collect(Collectors.toList());
                itemsByGroup.add(SalaryAcctResultDetailDTO.SalaryAcctResultDetailItemByGroupDTO.builder()
                        .salarySobItemGroupId(groupPO.getId())
                        .salarySobItemGroupName(groupPO.getName())
                        .salaryItems(items)
                        .sortedIndex(groupPO.getSortedIndex()).build());
            }
        }
        // 未分类
        List<SalarySobItemPO> noGroupItems = salarySobItemPOMap.getOrDefault(0L, Collections.emptyList());
        if (CollectionUtils.isNotEmpty(noGroupItems)) {
            List<SalaryAcctResultDetailDTO.SalaryAcctResultDetailItemDTO> items = noGroupItems.stream()
                    .map(salarySobItemPO -> convert2SalaryAcctResultDetailItemDTO(salarySobItemPO, salaryItemMap.get(salarySobItemPO.getSalaryItemId()), resultValueMap, formulaContentMap, lockItems))
                    .collect(Collectors.toList());
            itemsByGroup.add(SalaryAcctResultDetailDTO.SalaryAcctResultDetailItemByGroupDTO.builder()
                    .salarySobItemGroupId(0L)
                    .salarySobItemGroupName("未分类")
                    .salaryItems(items)
                    .sortedIndex(itemsByGroup.size()).build());
        }


//        // 公式项的值（不根据salaryItemPO的valueType判断是因为薪资项目的valueType属性改变后并不会同步更新薪资账套中的薪资项目的formulaId字段）
//        List<SalaryAcctResultDetailDTO.SalaryAcctResultDetailItemDTO> formulaItems = salarySobItemPOS.stream()
//                .filter(salarySobItemPO -> salarySobItemPO.getFormulaId() > 0)
//                .map(salarySobItemPO -> convert2SalaryAcctResultDetailItemDTO(salarySobItemPO, salaryItemMap.get(salarySobItemPO.getSalaryItemId()), resultValueMap))
//                .collect(Collectors.toList());
//        // 输入/导入项目的值
//        List<SalaryAcctResultDetailDTO.SalaryAcctResultDetailItemDTO> inputItems = salarySobItemPOS.stream()
//                .filter(salarySobItemPO -> salarySobItemPO.getFormulaId() <= 0)
//                .map(salarySobItemPO -> convert2SalaryAcctResultDetailItemDTO(salarySobItemPO, salaryItemMap.get(salarySobItemPO.getSalaryItemId()), resultValueMap))
//                .collect(Collectors.toList());
//        // TODO 临时处理，后续删除，将已发补发加入输入、导入
//        formulaItems.addAll(salarySobBackItemPOS.stream()
//                .map(salarySobBackItemPO -> backItemConvert2SalaryAcctResultDetailItemDTO(salarySobBackItemPO, salaryBackItemMap.get(salarySobBackItemPO.getSalaryItemId()), resultValueMap, salaryBackItemFormula))
//                .collect(Collectors.toList()));
        // 已发/补发项目的值
        List<SalaryAcctResultDetailDTO.SalaryAcctResultDetailItemDTO> issuedAndReissueItems = salarySobBackItemPOS.stream()
                .map(salarySobBackItemPO -> backItemConvert2SalaryAcctResultDetailItemDTO(salarySobBackItemPO, salaryBackItemMap.get(salarySobBackItemPO.getSalaryItemId()), resultValueMap, salaryBackItemFormula))
                .collect(Collectors.toList());
        return SalaryAcctResultDetailDTO.builder()
                .id(salaryAcctEmployee.getId())
                .employeeId(salaryAcctEmployee.getEmployeeId())
                .employeeInfos(employeeInfos)
//                .formulaItems(formulaItems)
//                .inputItems(inputItems)
                .itemsByGroup(itemsByGroup)
                .issuedAndReissueItems(issuedAndReissueItems)
                .build();
    }

    public static List<SalarySobItemGroupPO> sortGroup(List<SalarySobItemGroupPO> salarySobItemGroupPOS) {
        if (CollectionUtils.isEmpty(salarySobItemGroupPOS)) {
            return Collections.emptyList();
        }
        return salarySobItemGroupPOS.stream().sorted(Comparator.comparingInt(SalarySobItemGroupPO::getSortedIndex)).collect(Collectors.toList());
    }

    /**
     * 薪资账套的薪资项目按照sortedIndex排序
     */
    public static void sortItem(Map<Long, List<SalarySobItemPO>> salarySobItemPOMap) {
        for (Map.Entry<Long, List<SalarySobItemPO>> entry : salarySobItemPOMap.entrySet()) {
            List<SalarySobItemPO> items = entry.getValue();
            if (CollectionUtils.isNotEmpty(items)) {
                List<SalarySobItemPO> sortedValue = items.stream().sorted(Comparator.comparingInt(SalarySobItemPO::getSortedIndex)).collect(Collectors.toList());
                salarySobItemPOMap.put(entry.getKey(), sortedValue);
            }
        }
    }

    /**
     * 转换成薪资核算结果详情dto
     *
     * @param salarySobItemPO
     * @param salaryItemPO
     * @param resultValueMap
     * @return
     */
    private static SalaryAcctResultDetailDTO.SalaryAcctResultDetailItemDTO convert2SalaryAcctResultDetailItemDTO(SalarySobItemPO salarySobItemPO,
                                                                                                                 SalaryItemPO salaryItemPO,
                                                                                                                 Map<Long, String> resultValueMap,
                                                                                                                 Map<String, SalaryAcctResultListColumnDTO> formulaContentMap,
                                                                                                                 List<Long> lockItems) {

        SalaryValueTypeEnum salaryValueTypeEnum = SalaryValueTypeEnum.parseByValue(Optional.ofNullable(salarySobItemPO).map(SalarySobItemPO::getValueType).orElse(1));
        String itemFormulaContent;
        if (Objects.equals(salaryValueTypeEnum.getValue(), SalaryValueTypeEnum.FORMULA.getValue())) {
            itemFormulaContent = Optional.ofNullable(formulaContentMap.get(salarySobItemPO.getSalaryItemId().toString())).map(SalaryAcctResultListColumnDTO::getFormulaContent).orElse("");
        } else {
            itemFormulaContent = salaryValueTypeEnum == null ? "" : salaryValueTypeEnum.getDefaultLabel();
        }

        // 薪资项目的数据类型
        return SalaryAcctResultDetailDTO.SalaryAcctResultDetailItemDTO.builder()
                .salaryItemId(salarySobItemPO.getSalaryItemId())
                .salaryItemName(Optional.ofNullable(salaryItemPO).map(SalaryItemPO::getName).orElse(StringUtils.EMPTY))
                .resultValue(resultValueMap.getOrDefault(salarySobItemPO.getSalaryItemId(), StringUtils.EMPTY))
                .dataType(Optional.ofNullable(salaryItemPO).map(SalaryItemPO::getDataType).orElse(SalaryDataTypeEnum.NUMBER.getValue()))
                .itemFormulaContent(itemFormulaContent)
//                .canEdit(Objects.equals(Optional.ofNullable(salaryItemPO).map(SalaryItemPO::getUseInEmployeeSalary).orElse(0), 0))
                .canEdit(true)
                .pattern(salarySobItemPO.getPattern())
                .lockStatus(lockItems.contains(salarySobItemPO.getSalaryItemId()) ? LockStatusEnum.LOCK.getDefaultLabel() : LockStatusEnum.UNLOCK.getDefaultLabel())
                .build();
    }

    /**
     * 薪资回算项目转换成薪资核算结果详情dto
     *
     * @param salarySobBackItemPO
     * @param salaryItemPO
     * @param resultValueMap
     * @return
     */
    private static SalaryAcctResultDetailDTO.SalaryAcctResultDetailItemDTO backItemConvert2SalaryAcctResultDetailItemDTO(SalarySobBackItemPO salarySobBackItemPO,
                                                                                                                         SalaryItemPO salaryItemPO,
                                                                                                                         Map<Long, String> resultValueMap,
                                                                                                                         Map<Long, String> salaryBackItemFormula) {
        // 薪资项目的数据类型
        return SalaryAcctResultDetailDTO.SalaryAcctResultDetailItemDTO.builder()
                .salaryItemId(salarySobBackItemPO.getSalaryItemId())
                .salaryItemName(Optional.ofNullable(salaryItemPO).map(SalaryItemPO::getName).orElse(StringUtils.EMPTY))
                .resultValue(resultValueMap.getOrDefault(salarySobBackItemPO.getSalaryItemId(), StringUtils.EMPTY))
                .itemFormulaContent(salaryBackItemFormula.get(salarySobBackItemPO.getSalaryItemId()))
                .dataType(Optional.ofNullable(salarySobBackItemPO).map(SalarySobBackItemPO::getDataType).orElse(SalaryDataTypeEnum.NUMBER.getValue()))
                .canEdit(Objects.equals(Optional.ofNullable(salaryItemPO).map(SalaryItemPO::getUseInEmployeeSalary).orElse(0), 0))
                .build();
    }

    /**
     * 薪资核算结果保存参数转换成薪资核算结果po
     *
     * @param saveParam          前端保存参数
     * @param salaryAcctEmployee 薪资核算人员po
     * @param employeeId         当前登陆人员id
     * @return
     */
    public static List<SalaryAcctResultPO> convert2PO(List<SalaryAcctResultPO> salaryAcctResultPOSOld,
                                                      SalaryAcctResultSaveParam saveParam,
                                                      SalaryAcctEmployeePO salaryAcctEmployee,
                                                      Long employeeId) {
        if (CollectionUtils.isEmpty(saveParam.getItems())) {
            return Collections.emptyList();
        }
        // 获取薪资项目回算前的值
        Map<String, String> salaryAcctResultOldPOMap = salaryAcctResultPOSOld.stream()
                .collect(Collectors.groupingBy(p -> p.getSalaryAcctEmpId() + "-" + p.getSalaryItemId(),
                        Collectors.collectingAndThen(Collectors.maxBy(Comparator.comparing(SalaryAcctResultPO::getId)),
                                s -> s.map(SalaryAcctResultPO::getOriginResultValue).orElse(""))));
        Date now = new Date();
        return saveParam.getItems().stream()
                .map(e -> SalaryAcctResultPO.builder()
                        .salarySobId(salaryAcctEmployee.getSalarySobId())
                        .salaryItemId(e.getSalaryItemId())
                        .salaryAcctRecordId(salaryAcctEmployee.getSalaryAcctRecordId())
                        .salaryAcctEmpId(salaryAcctEmployee.getId())
                        .employeeId(salaryAcctEmployee.getEmployeeId())
                        .taxAgentId(salaryAcctEmployee.getTaxAgentId())
                        .resultValue(StringUtils.trim(e.getResultValue()))
                        .originResultValue(salaryAcctResultOldPOMap.get(saveParam.getSalaryAcctEmpId() + "-" + e.getSalaryItemId()))
                        .creator(employeeId)
                        .createTime(now)
                        .updateTime(now)
                        .deleteType(NumberUtils.INTEGER_ZERO)
                        .tenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY)
                        .build())
                .collect(Collectors.toList());
    }


    public static List<SalaryAcctResultPO> batchEditConvert2PO(Map<String, String> salaryAcctResultOldPOMap,
                                                               List<SalaryAcctResultSaveParam.SalaryAcctResultDetailItemParam> items,
                                                               SalaryAcctEmployeePO salaryAcctEmployee,
                                                               Long employeeId) {
        if (CollectionUtils.isEmpty(items) || ObjectUtil.isEmpty(salaryAcctEmployee)) {
            return Collections.emptyList();
        }
        Date now = new Date();
        return items.stream()
                .map(e -> SalaryAcctResultPO.builder()
                        .salarySobId(salaryAcctEmployee.getSalarySobId())
                        .salaryItemId(e.getSalaryItemId())
                        .salaryAcctRecordId(salaryAcctEmployee.getSalaryAcctRecordId())
                        .salaryAcctEmpId(salaryAcctEmployee.getId())
                        .employeeId(salaryAcctEmployee.getEmployeeId())
                        .taxAgentId(salaryAcctEmployee.getTaxAgentId())
                        .resultValue(StringUtils.trim(e.getResultValue()))
                        .originResultValue(salaryAcctResultOldPOMap.get(salaryAcctEmployee.getId() + "-" + e.getSalaryItemId()))
                        .creator(employeeId)
                        .createTime(now)
                        .updateTime(now)
                        .deleteType(NumberUtils.INTEGER_ZERO)
                        .tenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY)
                        .build())
                .collect(Collectors.toList());
    }

    public static Map<String, String> buildEmployeeFieldName() {
        Field[] declaredFields = SalaryFormulaEmployeeDTO.class.getDeclaredFields();
        Map<String, String> employeeFieldNameMap = Maps.newHashMapWithExpectedSize(declaredFields.length);
        for (Field declaredField : declaredFields) {
            if (!declaredField.isAnnotationPresent(SalaryFormulaVar.class)) {
                continue;
            }
            SalaryFormulaVar annotation = declaredField.getAnnotation(SalaryFormulaVar.class);
            employeeFieldNameMap.put(declaredField.getName(), SalaryI18nUtil.getI18nLabel(annotation.labelId(), annotation.defaultLabel()));
            employeeFieldNameMap.put(declaredField.getName() + "_type", annotation.dataType());
        }
        return employeeFieldNameMap;
    }

    public static ConsolidatedTaxDetailDTO convert2ConsolidatedTaxDetailDTO(DataCollectionEmployee simpleEmployee,
                                                                            TaxAgentPO taxAgent,
                                                                            List<SalarySobEmpFieldPO> salarySobEmpFields,
                                                                            List<SalaryItemPO> salaryItems,
                                                                            List<SalaryAcctEmployeePO> salaryAcctEmployees,
                                                                            List<SalarySobPO> salarySobs,
                                                                            List<SalaryAcctRecordPO> salaryAcctRecords,
                                                                            List<SalaryAcctResultPO> salaryAcctResults) {
        return ConsolidatedTaxDetailDTO.builder()
//                .employeeInfo(buildConsolidatedTaxationEmpInfo(simpleEmployee, taxAgent, salarySobEmpFields))
//                .salaryAcctResult(buildConsolidatedTaxationAcctResult(salaryItems, salaryAcctEmployees, salarySobs, salaryAcctRecords, salaryAcctResults))
                .build();
    }

    /**
     * 合并计税详情-员工信息
     *
     * @param simpleEmployee
     * @param salarySobEmpFields
     * @return
     */
//    private static WeaForm buildConsolidatedTaxationEmpInfo(DataCollectionEmployee simpleEmployee, TaxAgent taxAgent, List<SalarySobEmpFieldPO> salarySobEmpFields) {
//        Map<String, String> employeeFieldNameMap = buildEmployeeFieldName();
//        Map<String, String> fieldValueMap = SalaryAcctFormulaBO.convert2FormulaEmployee(simpleEmployee);
//        fieldValueMap.put("taxAgentName", taxAgent.getName());
//        Map<String, Object> data = Maps.newHashMap();
//        Map<String, WeaFormItem> items = Maps.newHashMap();
//        List<List<WeaFormLayout>> layout = Lists.newArrayList();
//        List<WeaFormLayout> temp = Lists.newArrayList();
//        for (SalarySobEmpFieldPO field : salarySobEmpFields) {
//            // 字段属性
//            WeaFormItem weaFormItem = new WeaFormItem(WeaFormItemType.INPUT);
//            weaFormItem.setReadOnly(true);
//            weaFormItem.setValue(fieldValueMap.getOrDefault(field.getFieldCode(), ""));
//            items.put(field.getFieldCode(), weaFormItem);
//            // 字段布局
//            if (temp.size() == 3) {
//                layout.add(new ArrayList<>(temp));
//                temp = Lists.newArrayList();
//            }
//            WeaFormLayout weaFormLayout = new WeaFormLayout(field.getFieldCode(), employeeFieldNameMap.getOrDefault(field.getFieldCode(), ""), new String[]{field.getFieldCode()});
//            temp.add(weaFormLayout);
//            // 字段的值
//            data.put(field.getFieldCode(), weaFormItem.getValue());
//        }
//        if (CollectionUtils.isNotEmpty(temp)) {
//            layout.add(new ArrayList<>(temp));
//        }
//        WeaForm weaForm = new WeaForm();
//        weaForm.setData(data);
//        weaForm.setItems(items);
//        weaForm.setLayout(layout);
//        return weaForm;
//    }


    /**
     * 合并计税详情-核算结果列表
     *
     * @param salaryItems
     * @param salaryAcctResults
     * @return
     */
//    private static WeaTable<Map<String, Object>> buildConsolidatedTaxationAcctResult(List<SalaryItemPO> salaryItems,
//                                                                                     List<SalaryAcctEmployeePO> salaryAcctEmployees,
//                                                                                     List<SalarySobPO> salarySobs,
//                                                                                     List<SalaryAcctRecordPO> salaryAcctRecords,
//                                                                                     List<SalaryAcctResultPO> salaryAcctResults) {
//        // 薪资核算人员
//        Map<Long, SalaryAcctEmployeePO> salaryAcctEmployeeMap = SalaryEntityUtil.convert2Map(salaryAcctEmployees, SalaryAcctEmployeePO::getId);
//        // 薪资账套
//        Map<Long, String> salarySobNameMap = SalaryEntityUtil.convert2Map(salarySobs, SalarySobPO::getId, SalarySobPO::getName);
//        // 薪资核算记录
//        Map<Long, SalaryAcctRecordPO> salaryAcctRecordMap = SalaryEntityUtil.convert2Map(salaryAcctRecords, SalaryAcctRecordPO::getId);
//        // 薪资核算结果
//        Map<Long, List<SalaryAcctResultPO>> salaryAcctResultMap = SalaryEntityUtil.group2Map(salaryAcctResults, SalaryAcctResultPO::getSalaryAcctEmpId);
//        List<WeaTableColumn> weaTableColumns = Lists.newArrayList(new WeaTableColumn("核算批次", "salarySobName"));
//        weaTableColumns.addAll(salaryItems.stream()
//                .map(e -> new WeaTableColumn(e.getName(), "" + e.getId(), false))
//                .collect(Collectors.toList()));
//        WeaTable<Map<String, Object>> weaTable = new WeaTable<>();
//        weaTable.setTableType(WeaTableTypeEnum.NONE);
//        weaTable.setCurrent(0);
//        weaTable.setPageSize(salaryAcctResultMap.size());
//        weaTable.setTotal(salaryAcctResultMap.size());
//        weaTable.setColumns(weaTableColumns);
//        if (CollectionUtils.isEmpty(salaryAcctResults)) {
//            return weaTable;
//        }
//        List<Map<String, Object>> data = Lists.newArrayList();
//        salaryAcctResultMap.forEach((k, v) -> {
//            // 薪资核算的结果
//            Map<String, Object> valueMap = SalaryEntityUtil.convert2Map(v, e -> "" + e.getSalaryItemId(), SalaryAcctResultPO::getResultValue);
//            // 核算批次
//            SalaryAcctEmployeePO salaryAcctEmployeePO = salaryAcctEmployeeMap.get(k);
//            SalaryAcctRecordPO salaryAcctRecordPO = salaryAcctRecordMap.get(salaryAcctEmployeePO.getSalaryAcctRecordId());
//            String salarySobName = salarySobNameMap.getOrDefault(salaryAcctRecordPO.getSalarySobId(), "");
//            valueMap.put("salarySobName", "第" + salaryAcctRecordPO.getAcctTimes() + "次（" + salarySobName + "）");
//            data.add(valueMap);
//        });
//        weaTable.setData(data);
//        weaTable.setDisplayData(data);
//        return weaTable;
//    }

    /**
     * 薪资核算结果临时存储转成薪资核算结果po
     *
     * @param temps
     * @return
     */
    public static List<SalaryAcctResultPO> convert2ResultPO(Collection<SalaryAcctResultTempPO> temps) {
        if (CollectionUtils.isEmpty(temps)) {
            return Collections.emptyList();
        }
        return temps.stream().map(e -> {
            SalaryAcctResultPO salaryAcctResult = new SalaryAcctResultPO();
            BeanUtils.copyProperties(e, salaryAcctResult);
            return salaryAcctResult;
        }).collect(Collectors.toList());
    }


}
